Skip to content

fix(ts): use type-only imports in TS variants (fixes TS1484 in stock Vite react-ts apps) - #1018

Open
noron12234 wants to merge 1 commit into
DavidHDev:mainfrom
noron12234:feat/fix-type-only-imports
Open

fix(ts): use type-only imports in TS variants (fixes TS1484 in stock Vite react-ts apps)#1018
noron12234 wants to merge 1 commit into
DavidHDev:mainfrom
noron12234:feat/fix-type-only-imports

Conversation

@noron12234

@noron12234 noron12234 commented Jul 31, 2026

Copy link
Copy Markdown

The problem

React Bits components are meant to be copied into a consumer's project. A stock
npm create vite@latest -- --template react-ts project ships
verbatimModuleSyntax: true, and under that flag every TS variant that imports
a type through a value import fails to compile.

Reproduction, against main as it is today:

npm create vite@latest repro -- --template react-ts
cd repro && npm i
curl -o src/Magnet.tsx https://raw.githubusercontent.com/DavidHDev/react-bits/main/src/ts-default/Animations/Magnet/Magnet.tsx
npx tsc --noEmit
src/Magnet.tsx(1,46): error TS1484: 'ReactNode' is a type and must be imported
  using a type-only import when 'verbatimModuleSyntax' is enabled.
src/Magnet.tsx(1,57): error TS1484: 'HTMLAttributes' is a type and must be
  imported using a type-only import when 'verbatimModuleSyntax' is enabled.

With this branch, the same check exits 0.

Why CI is green on main even though this is broken

This repo's own tsconfig.json sets isolatedModules but not
verbatimModuleSyntax, so tsc here never raises TS1484. The breakage only
appears downstream, in the consumer project — which is the only place these
files are ever compiled. That is why there is no failing test to point at.

If you would rather catch this in CI going forward, adding
"verbatimModuleSyntax": true to tsconfig.json would do it. I left that out
of this PR deliberately since it changes your build config.

What this changes

83 .tsx files, mechanically: type-only specifiers (type Foo) for imports
that are types. +126 / -94. No runtime change — verbatimModuleSyntax
governs emit of import statements only.

Generated public/r/** artifacts are not included; npm run build runs
registry:build and regenerates them.

Precedent: magicui merged the identical fix for the same root cause in
magicuidesign/magicui#993.

Reviewing this

The diff is wide but shallow — one line per file in most cases. The mechanical
check is that every added type keyword sits in front of an identifier that is
only ever used in a type position.

@noron12234

Copy link
Copy Markdown
Author

Follow-up: I understated the impact in the description. For at least one component this is not a tsc complaint at all — it breaks the bundler and the dev server, with TypeScript entirely out of the picture.

Ballpit imports WebGLRendererParameters from three, which is a type. three does not export it at runtime, and unlike the other cases the name survives into the emitted module.

Production build, stock Vite React-TS app, tsc skipped so only the bundler runs:

$ npx vite build
error during build:
Build failed with 1 error:
[MISSING_EXPORT] "WebGLRendererParameters" is not exported by "node_modules/three/build/three.module.js".
 4 │ import { ACESFilmicToneMapping, ..., WebGLRenderer, WebGLRendererParameters } from "three";
   │                                                     ╰───────────── Missing export

Dev server, same app, measured with Playwright:

page error component renders
current main The requested module '/node_modules/.vite/deps/three.js' does not provide an export named 'WebGLRendererParameters' no — blank page
this PR none yes

So Ballpit's two TS variants cannot be built or run at all in a stock Vite app today, regardless of anyone's tsconfig.

Why this one and not Silk: in Silk, IUniform is its own single-specifier import { IUniform } from 'three', and an import statement whose only specifier is unused after type erasure is dropped before it reaches the bundler. Ballpit's sits inside a 21-name import whose other names are genuine values, so the statement survives — and carries the type name with it. That is why the failure looks inconsistent across components rather than universal.

Nothing changes in the diff; the type modifier this PR adds at Ballpit.tsx:25 is what fixes it. Just wanted the severity on the record, since "compile error" undersells a component that currently fails vite build outright.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request fixes TypeScript build errors (TS1484) in the TypeScript component variants by converting type-only named imports (from react, motion/react, three, and @react-three/fiber) into explicit type imports using the inline type modifier, aligning with verbatimModuleSyntax defaults in stock Vite React-TS projects.

Changes:

  • Updated TS variant files to use type-only import specifiers for bindings that are types (e.g. Transition, Variants, RootState, IUniform, JSX, etc.).
  • Applied the same mechanical import fix consistently across both TS variants (ts-default and ts-tailwind), with only formatting rewraps where needed.

Reviewed changes

Copilot reviewed 83 out of 83 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/ts-tailwind/TextAnimations/VariableProximity/VariableProximity.tsx Converts React type imports to inline type specifiers.
src/ts-tailwind/TextAnimations/TextType/TextType.tsx Marks ElementType as type-only in React import.
src/ts-tailwind/TextAnimations/Shuffle/Shuffle.tsx Marks JSX as type-only in React import.
src/ts-tailwind/TextAnimations/ScrollReveal/ScrollReveal.tsx Marks ReactNode/RefObject as type-only in React import.
src/ts-tailwind/TextAnimations/ScrollFloat/ScrollFloat.tsx Marks ReactNode/RefObject as type-only in React import.
src/ts-tailwind/TextAnimations/RotatingText/RotatingText.tsx Marks Transition as type-only in motion/react import.
src/ts-tailwind/TextAnimations/GradientText/GradientText.tsx Marks ReactNode as type-only in React import.
src/ts-tailwind/TextAnimations/GlitchText/GlitchText.tsx Marks FC/CSSProperties as type-only in React import.
src/ts-tailwind/TextAnimations/CurvedLoop/CurvedLoop.tsx Marks FC/PointerEvent as type-only in React import.
src/ts-tailwind/TextAnimations/CircularText/CircularText.tsx Marks Transition as type-only in motion/react import.
src/ts-tailwind/TextAnimations/BlurText/BlurText.tsx Marks Transition/Easing as type-only in motion/react import.
src/ts-tailwind/Components/Stepper/Stepper.tsx Marks React and Motion type imports as type-only.
src/ts-tailwind/Components/SpecularButton/SpecularButton.tsx Marks React DOM/types imports as type-only.
src/ts-tailwind/Components/PixelCard/PixelCard.tsx Marks JSX as type-only in React import.
src/ts-tailwind/Components/OptionWheel/OptionWheel.tsx Marks CSSProperties as type-only in React import.
src/ts-tailwind/Components/ModelViewer/ModelViewer.tsx Marks FC as type-only in React import.
src/ts-tailwind/Components/LineSidebar/LineSidebar.tsx Marks CSSProperties as type-only in React import.
src/ts-tailwind/Components/InfiniteMenu/InfiniteMenu.tsx Marks FC/MutableRefObject as type-only in React import.
src/ts-tailwind/Components/FluidGlass/FluidGlass.tsx Marks ReactNode/ThreeElements as type-only imports.
src/ts-tailwind/Components/DecayCard/DecayCard.tsx Marks ReactNode as type-only in React import.
src/ts-tailwind/Components/Carousel/Carousel.tsx Marks PanInfo/JSX as type-only imports.
src/ts-tailwind/Components/CardSwap/CardSwap.tsx Marks ReactElement/ReactNode/RefObject as type-only imports.
src/ts-tailwind/Components/AnimatedList/AnimatedList.tsx Marks React event/node types as type-only imports.
src/ts-tailwind/Backgrounds/Waves/Waves.tsx Marks CSSProperties as type-only in React import.
src/ts-tailwind/Backgrounds/Silk/Silk.tsx Marks RootState/IUniform as type-only imports.
src/ts-tailwind/Backgrounds/Hyperspeed/Hyperspeed.tsx Marks FC as type-only in React import.
src/ts-tailwind/Backgrounds/GridMotion/GridMotion.tsx Marks FC/ReactNode as type-only in React import.
src/ts-tailwind/Backgrounds/Dither/Dither.tsx Marks ThreeEvent as type-only in @react-three/fiber import.
src/ts-tailwind/Backgrounds/Beams/Beams.tsx Marks FC/ReactNode as type-only in React import.
src/ts-tailwind/Backgrounds/Ballpit/Ballpit.tsx Marks WebGLRendererParameters as type-only in three import.
src/ts-tailwind/Animations/Strands/Strands.tsx Marks CSSProperties as type-only in React import.
src/ts-tailwind/Animations/StickerPeel/StickerPeel.tsx Marks CSSProperties as type-only in React import.
src/ts-tailwind/Animations/ShapeBlur/ShapeBlur.tsx Marks FC as type-only in React import.
src/ts-tailwind/Animations/PixelTransition/PixelTransition.tsx Marks CSSProperties as type-only in React import.
src/ts-tailwind/Animations/PixelTrail/PixelTrail.tsx Marks CanvasProps/ThreeEvent as type-only in @react-three/fiber import.
src/ts-tailwind/Animations/OrbitImages/OrbitImages.tsx Marks ReactNode as type-only in React import.
src/ts-tailwind/Animations/MagnetLines/MagnetLines.tsx Marks CSSProperties as type-only in React import.
src/ts-tailwind/Animations/Magnet/Magnet.tsx Marks ReactNode/HTMLAttributes as type-only in React import.
src/ts-tailwind/Animations/ImageTrail/ImageTrail.tsx Marks JSX as type-only in React import.
src/ts-tailwind/Animations/GradualBlur/GradualBlur.tsx Marks CSSProperties/PropsWithChildren as type-only in React import.
src/ts-tailwind/Animations/ElectricBorder/ElectricBorder.tsx Marks CSSProperties/ReactNode as type-only in React import.
src/ts-tailwind/Animations/Crosshair/Crosshair.tsx Marks RefObject as type-only in React import.
src/ts-default/TextAnimations/VariableProximity/VariableProximity.tsx Converts React type imports to inline type specifiers.
src/ts-default/TextAnimations/TrueFocus/TrueFocus.tsx Marks RefObject as type-only in React import.
src/ts-default/TextAnimations/TextType/TextType.tsx Marks ElementType as type-only in React import.
src/ts-default/TextAnimations/ScrollReveal/ScrollReveal.tsx Marks ReactNode/RefObject as type-only in React import.
src/ts-default/TextAnimations/ScrollFloat/ScrollFloat.tsx Marks ReactNode/RefObject as type-only in React import.
src/ts-default/TextAnimations/RotatingText/RotatingText.tsx Marks Transition as type-only in motion/react import.
src/ts-default/TextAnimations/GradientText/GradientText.tsx Marks ReactNode as type-only in React import.
src/ts-default/TextAnimations/GlitchText/GlitchText.tsx Marks FC/CSSProperties as type-only in React import.
src/ts-default/TextAnimations/CurvedLoop/CurvedLoop.tsx Marks FC/PointerEvent as type-only in React import.
src/ts-default/TextAnimations/CircularText/CircularText.tsx Marks Transition as type-only in motion/react import.
src/ts-default/TextAnimations/BlurText/BlurText.tsx Marks Transition as type-only in motion/react import.
src/ts-default/Components/Stepper/Stepper.tsx Marks React/Motion type imports as type-only.
src/ts-default/Components/SpecularButton/SpecularButton.tsx Marks React DOM/types imports as type-only.
src/ts-default/Components/PixelCard/PixelCard.tsx Marks JSX as type-only in React import.
src/ts-default/Components/OptionWheel/OptionWheel.tsx Marks CSSProperties as type-only in React import.
src/ts-default/Components/ModelViewer/ModelViewer.tsx Marks FC as type-only in React import.
src/ts-default/Components/LineSidebar/LineSidebar.tsx Marks CSSProperties as type-only in React import.
src/ts-default/Components/InfiniteMenu/InfiniteMenu.tsx Marks FC/MutableRefObject as type-only in React import.
src/ts-default/Components/FluidGlass/FluidGlass.tsx Marks ReactNode/ThreeElements as type-only imports.
src/ts-default/Components/DecayCard/DecayCard.tsx Marks ReactNode as type-only in React import.
src/ts-default/Components/Carousel/Carousel.tsx Marks PanInfo as type-only in motion/react import.
src/ts-default/Components/CardSwap/CardSwap.tsx Marks ReactElement/ReactNode/RefObject as type-only imports.
src/ts-default/Components/AnimatedList/AnimatedList.tsx Marks React event/node types as type-only imports.
src/ts-default/Backgrounds/Waves/Waves.tsx Marks CSSProperties as type-only in React import.
src/ts-default/Backgrounds/Silk/Silk.tsx Marks RootState/IUniform as type-only imports.
src/ts-default/Backgrounds/Hyperspeed/Hyperspeed.tsx Marks FC as type-only in React import.
src/ts-default/Backgrounds/GridMotion/GridMotion.tsx Marks FC/ReactNode as type-only in React import.
src/ts-default/Backgrounds/Dither/Dither.tsx Marks ThreeEvent as type-only in @react-three/fiber import.
src/ts-default/Backgrounds/Beams/Beams.tsx Marks FC/ReactNode as type-only in React import.
src/ts-default/Backgrounds/Ballpit/Ballpit.tsx Marks WebGLRendererParameters as type-only in three import.
src/ts-default/Animations/Strands/Strands.tsx Marks CSSProperties as type-only in React import.
src/ts-default/Animations/StickerPeel/StickerPeel.tsx Marks CSSProperties as type-only in React import.
src/ts-default/Animations/PixelTransition/PixelTransition.tsx Marks CSSProperties as type-only in React import.
src/ts-default/Animations/PixelTrail/PixelTrail.tsx Marks CanvasProps/ThreeEvent as type-only in @react-three/fiber import.
src/ts-default/Animations/OrbitImages/OrbitImages.tsx Marks ReactNode as type-only in React import.
src/ts-default/Animations/MagnetLines/MagnetLines.tsx Marks CSSProperties as type-only in React import.
src/ts-default/Animations/Magnet/Magnet.tsx Marks ReactNode/HTMLAttributes as type-only in React import.
src/ts-default/Animations/ImageTrail/ImageTrail.tsx Marks JSX as type-only in React import.
src/ts-default/Animations/GradualBlur/GradualBlur.tsx Marks CSSProperties/PropsWithChildren as type-only in React import.
src/ts-default/Animations/ElectricBorder/ElectricBorder.tsx Marks CSSProperties/ReactNode as type-only in React import.
src/ts-default/Animations/Crosshair/Crosshair.tsx Marks RefObject as type-only in React import.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@noron12234

Copy link
Copy Markdown
Author

Pushed 6ad9ba0: the registry artifacts were missing from this PR.

public/r/*.json embeds the component source verbatim and is what the jsrepo CLI writes into a user's project, so fixing only src/ left the shipped payload with the value imports intact. That includes Ballpit's WebGLRendererParameters, which is the one that makes rolldown fail the build outright rather than just upsetting tsc.

Regenerated with npm run registry:build; 83 entries change, all TS variants.

@noron12234
noron12234 force-pushed the feat/fix-type-only-imports branch from 45a3229 to 9ff31a2 Compare August 9, 2026 16:44
The TS-CSS and TS-TW variants shipped through the registry import
type-only bindings (ReactNode, FC, CSSProperties, Transition, IUniform,
RootState, ThreeEvent, ...) as value imports.

TypeScript's own `--template react-ts` scaffold enables
`verbatimModuleSyntax`, so every one of these is a hard TS1484 compile
error the moment someone installs a TS variant into a stock Vite app.

Adds the inline `type` modifier at 132 specifiers across 83 files,
matching the style already used elsewhere in the same imports (e.g.
RotatingText already writes `type VariantLabels`). No runtime or type
semantics change.
@noron12234
noron12234 force-pushed the feat/fix-type-only-imports branch from 9ff31a2 to cb8bde6 Compare August 10, 2026 15:31
@noron12234

Copy link
Copy Markdown
Author

Slimmed this down and rewrote the description with a reproduction.

Two things changed since you last would have seen it:

  • The generated public/r/** artifacts are gone — the diff is source only now. That was 83 of the ~166 files and it was pure noise, npm run build regenerates them.
  • The description now has a copy-pasteable repro showing tsc failing on main in a stock Vite react-ts project, and passing on this branch.

Worth calling out explicitly: this repo's own tsconfig.json doesn't set verbatimModuleSyntax, so your CI genuinely cannot catch this — the break only shows up in the consumer's project after they copy a component. That's why there's no failing test here to point at.

Happy to split it per-category if a single 83-file diff is awkward to review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants